/**
 * Copyright (c) 2020-2024, huli.com
 * All rights reserved.
 */
package com.xiaohujr.xuexue.leetcode.interview;

import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 两个生产者，两个消费者，一个仓库
 * 生产者可以同时生产，消费者可以同时消费，仓库最多可以装10个货物
 * 四者同时启动，仓库为空
 * 仓库存在两种互斥的状态：补货，出货；仓库满时，从补货->出货；仓库清空时，从出货->补货
 * 每个生产者每次只能生产一个货物，用sleep 1s表示生产货物的过程
 * 生产者可以积压货物在手中；
 * 仓库是出货状态时，生产者必须休息
 * 两个消费者每次只能消费1个货物，用sleep 1s表示消费货物的过程
 * 仓库是补货状态时，消费者必须休息
 *
 * @author Xue Xue (xuexue1@huli.com)
 * @version 1.0
 * @since 2021/2/1
 */
public class ProducerConsumer {
    private static final int MAX_SIZE = 10;
    private AtomicInteger storage = new AtomicInteger(0);
    private Lock lock = new ReentrantLock(false);
    private Condition full = lock.newCondition();
    private Condition empty = lock.newCondition();


    private Runnable addStorage = () -> {
        System.out.print(Thread.currentThread().getName()+"我开始工作了：：：");
        while (true) {
            lock.lock();
            try {
                System.out.print(Thread.currentThread().getName() + "::增库存前：" + storage.get() + "------");
                if (storage.get() == MAX_SIZE) {
                    full.signal();
                    try {
                        empty.await();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }else {
                    Thread.sleep(200);

                    System.out.print(Thread.currentThread().getName() + "::增库存后：" + storage.addAndGet(1) + "-----");
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                System.out.println(Thread.currentThread().getName() + "::释放锁咯");
                lock.unlock();
                try {
                    Thread.sleep(200);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }

    };

    private Runnable decStorage = () -> {
        System.out.print(Thread.currentThread().getName()+"我开始工作了：：：");
        while (true) {
            lock.lock();
            System.out.print(Thread.currentThread().getName() + "::出库前：" + storage.get() + "-----");
            try {
                if (storage.get() == 0) {
                    empty.signalAll();
                    try {
                        full.await();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }else {
                    Thread.sleep(200);

                    System.out.print(Thread.currentThread().getName() + "::出库啦：" + storage.decrementAndGet() + "-----");
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                System.out.println(Thread.currentThread().getName() + "::释放锁咯");
                lock.unlock();
                try {
                    Thread.sleep(200);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    };

    public static void main(String[] args) {
        ProducerConsumer producerConsumer = new ProducerConsumer();
        Thread threadProducerA = new Thread(producerConsumer.addStorage, "ProducerT1");
        Thread threadProducerB = new Thread(producerConsumer.addStorage, "ProducerT2");
        Thread threadConsumerA = new Thread(producerConsumer.decStorage, "ConsumerT1");
        Thread threadConsumerB = new Thread(producerConsumer.decStorage, "ConsumerT2");

        threadProducerA.start();
        threadProducerB.start();
        threadConsumerA.start();
        threadConsumerB.start();
    }


}
